Actual source code: ex4.c

  1: /*$Id: ex4.c,v 1.11 2001/04/10 19:37:11 bsmith Exp $*/
  2: /*
  3:        The Problem:
  4:            Solve the convection-diffusion equation:
  5:            
  6:              u_t+a*(u_x+u_y)=epsilon*(u_xx+u_yy)
  7:              u=0 at x=0, y=0
  8:              u_x=0 at x=1
  9:              u_y=0 at y=1
 10:         
 11:        This program tests the routine of computing the Jacobian by the 
 12:        finite difference method as well as PETSc with PVODE.

 14: */

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

 18:  #include petscsys.h
 19:  #include petscts.h

 21: extern int Monitor(TS,int,double,Vec,void *);
 22: extern int Initial(Vec,void *);

 24: typedef struct
 25: {
 26:   int                 m;        /* the number of mesh points in x-direction */
 27:   int                 n;      /* the number of mesh points in y-direction */
 28:   double         dx;     /* the grid space in x-direction */
 29:   double        dy;     /* the grid space in y-direction */
 30:   double        a;      /* the convection coefficient    */
 31:   double        epsilon; /* the diffusion coefficient    */
 32: } Data;

 34: /* two temporal functions */
 35: extern int FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
 36: extern int FormFunction(SNES,Vec,Vec,void*);
 37: extern int RHSFunction(TS,double,Vec,Vec,void*);
 38: extern int RHSJacobian(TS,double,Vec,Mat*,Mat*,MatStructure *,void*);

 40: /* the initial function */
 41: double f_ini(double x,double y)
 42: {
 43:   double f;
 44:   f=exp(-20.0*(pow(x-0.5,2.0)+pow(y-0.5,2.0)));
 45:   return f;
 46: }


 49: #define linear_no_matrix       0
 50: #define linear_no_time         1
 51: #define linear                 2
 52: #define nonlinear_no_jacobian  3
 53: #define nonlinear              4

 55: int main(int argc,char **argv)
 56: {
 57:   int           ierr,time_steps = 100,steps,size;
 58:   Vec           global;
 59:   double        dt,ftime;
 60:   TS            ts;
 61:   PetscViewer        viewfile;
 62:   MatStructure  A_structure;
 63:   Mat           A = 0;
 64:   TSProblemType tsproblem = TS_NONLINEAR; /* Need to be TS_NONLINEAR */
 65:   SNES          snes;
 66:   Vec                 x;
 67:   Data                data;
 68:   int                 mn;
 69: #if defined(PETSC_HAVE_PVODE) && !defined(__cplusplus)
 70:   PC                pc;
 71:   PetscViewer   viewer;
 72:   char          pcinfo[120],tsinfo[120];
 73: #endif

 75:   PetscInitialize(&argc,&argv,(char*)0,help);
 76:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 77: 
 78:   /* set Data */
 79:   data.m = 9;
 80:   data.n = 9;
 81:   data.a = 1.0;
 82:   data.epsilon = 0.1;
 83:   data.dx = 1.0/(data.m+1.0);
 84:   data.dy = 1.0/(data.n+1.0);
 85:   mn = (data.m)*(data.n);

 87:   PetscOptionsGetInt(PETSC_NULL,"-time",&time_steps,PETSC_NULL);
 88: 
 89:   /* set initial conditions */
 90:   VecCreate(PETSC_COMM_WORLD,PETSC_DECIDE,mn,&global);
 91:   VecSetFromOptions(global);
 92:   Initial(global,&data);
 93:   VecDuplicate(global,&x);
 94: 
 95:   /* make timestep context */
 96:   TSCreate(PETSC_COMM_WORLD,tsproblem,&ts);
 97:   TSSetMonitor(ts,Monitor,PETSC_NULL,PETSC_NULL);

 99:   dt = 0.1;

101:   /*
102:     The user provides the RHS and Jacobian
103:   */
104:   MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,mn,mn,&A);
105:   MatSetFromOptions(A);

107:   /* Create SNES context  */
108:   SNESCreate(PETSC_COMM_WORLD,SNES_NONLINEAR_EQUATIONS,&snes);
109: 

111:   /* setting the RHS function and the Jacobian's non-zero structutre */
112:   SNESSetFunction(snes,global,FormFunction,&data);
113:   SNESSetJacobian(snes,A,A,FormJacobian,&data);

115:   /* set TSPVodeRHSFunction and TSPVodeRHSJacobian, so PETSc will pick up the 
116:      RHS function from SNES and compute the Jacobian by FD */
117:   /*
118:   TSSetRHSFunction(ts,TSPVodeSetRHSFunction,snes);
119:   TSPVodeSetRHSJacobian(ts,0.0,global,&A,&A,&A_structure,snes);
120:   TSSetRHSJacobian(ts,A,A,TSPVodeSetRHSJacobian,snes);
121:   */
122: 
123:   TSSetRHSFunction(ts,RHSFunction,&data);
124:   RHSJacobian(ts,0.0,global,&A,&A,&A_structure,&data);
125:   TSSetRHSJacobian(ts,A,A,RHSJacobian,&data);

127:   /* Use PVODE */
128:   TSSetType(ts,TS_PVODE);

130:   TSSetFromOptions(ts);

132:   TSSetInitialTimeStep(ts,0.0,dt);
133:   TSSetDuration(ts,time_steps,1);
134:   TSSetSolution(ts,global);


137:   /* Pick up a Petsc preconditioner */
138:   /* one can always set method or preconditioner during the run time */
139: #if defined(PETSC_HAVE_PVODE) && !defined(__cplusplus)
140:   TSPVodeGetPC(ts,&pc);
141:   PCSetType(pc,PCJACOBI);
142:   TSPVodeSetType(ts,PVODE_BDF);
143:   /* TSPVodeSetMethodFromOptions(ts); */
144: #endif

146:   TSSetUp(ts);
147:   TSStep(ts,&steps,&ftime);

149:   TSGetSolution(ts,&global);
150:   PetscViewerASCIIOpen(PETSC_COMM_SELF,"out.m",&viewfile);
151:   PetscViewerSetFormat(viewfile,PETSC_VIEWER_ASCII_MATLAB);
152:   VecView(global,viewfile);

154: #if defined(PETSC_HAVE_PVODE) && !defined(__cplusplus)
155:   /* extracts the PC  from ts */
156:   TSPVodeGetPC(ts,&pc);
157:   PetscViewerStringOpen(PETSC_COMM_WORLD,tsinfo,120,&viewer);
158:   TSView(ts,viewer);
159:   PetscViewerStringOpen(PETSC_COMM_WORLD,pcinfo,120,&viewer);
160:   PCView(pc,viewer);
161:   PetscPrintf(PETSC_COMM_WORLD,"%d Procs,%s Preconditioner,%sn",
162:                      size,tsinfo,pcinfo);
163:   PCDestroy(pc);
164: #endif

166:   /* free the memories */
167:   TSDestroy(ts);
168:   VecDestroy(global);
169:   if (A) {ierr= MatDestroy(A);}
170:   PetscFinalize();
171:   return 0;
172: }

174: /* -------------------------------------------------------------------*/
175: int Initial(Vec global,void *ctx)
176: {
177:   Data *data = (Data*)ctx;
178:   int m;
179:   int row,col;
180:   double x,y,dx,dy;
181:   Scalar *localptr;
182:   int    i,mybase,myend,ierr,locsize;

184:   /* make the local  copies of parameters */
185:   m = data->m;
186:   dx = data->dx;
187:   dy = data->dy;

189:   /* determine starting point of each processor */
190:   VecGetOwnershipRange(global,&mybase,&myend);
191:   VecGetLocalSize(global,&locsize);

193:   /* Initialize the array */
194:   VecGetArray(global,&localptr);

196:   for (i=0; i<locsize; i++) {
197:     row = 1+(mybase+i)-((mybase+i)/m)*m;
198:     col = (mybase+i)/m+1;
199:     x = dx*row;
200:     y = dy*col;
201:     localptr[i] = f_ini(x,y);
202:   }
203: 
204:   VecRestoreArray(global,&localptr);
205:   return 0;
206: }

208: int Monitor(TS ts,int step,double time,Vec global,void *ctx)
209: {
210:   VecScatter scatter;
211:   IS from,to;
212:   int i,n,*idx;
213:   Vec tmp_vec;
214:   int      ierr;
215:   Scalar   *tmp;

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

220:   /* Set the index sets */
221:   PetscMalloc(n*sizeof(int),&idx);
222:   for(i=0; i<n; i++) idx[i]=i;
223: 
224:   /* Create local sequential vectors */
225:   VecCreateSeq(PETSC_COMM_SELF,n,&tmp_vec);

227:   /* Create scatter context */
228:   ISCreateGeneral(PETSC_COMM_SELF,n,idx,&from);
229:   ISCreateGeneral(PETSC_COMM_SELF,n,idx,&to);
230:   VecScatterCreate(global,from,tmp_vec,to,&scatter);
231:   VecScatterBegin(global,tmp_vec,INSERT_VALUES,SCATTER_FORWARD,scatter);
232:   VecScatterEnd(global,tmp_vec,INSERT_VALUES,SCATTER_FORWARD,scatter);

234:   VecGetArray(tmp_vec,&tmp);
235:   PetscPrintf(PETSC_COMM_WORLD,"At t =%14.6e u= %14.6e at the center n",time,PetscRealPart(tmp[n/2]));
236:   VecRestoreArray(tmp_vec,&tmp);

238:   PetscFree(idx);
239:   return 0;
240: }


243: int FormFunction(SNES snes,Vec globalin,Vec globalout,void *ptr)
244: {
245:   Data *data = (Data*)ptr;
246:   int m,n,mn;
247:   double dx,dy;
248:   double xc,xl,xr,yl,yr;
249:   double a,epsilon;
250:   Scalar *inptr,*outptr;
251:   int i,j,len,ierr;

253:   IS from,to;
254:   int *idx;
255:   VecScatter scatter;
256:   Vec tmp_in,tmp_out;

258:   m = data->m;
259:   n = data->n;
260:   mn = m*n;
261:   dx = data->dx;
262:   dy = data->dy;
263:   a = data->a;
264:   epsilon = data->epsilon;

266:   xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy));
267:   xl = 0.5*a/dx+epsilon/(dx*dx);
268:   xr = -0.5*a/dx+epsilon/(dx*dx);
269:   yl = 0.5*a/dy+epsilon/(dy*dy);
270:   yr = -0.5*a/dy+epsilon/(dy*dy);
271: 
272:   /* Get the length of parallel vector */
273:   VecGetSize(globalin,&len);

275:   /* Set the index sets */
276:   PetscMalloc(len*sizeof(int),&idx);
277:   for(i=0; i<len; i++) idx[i]=i;
278: 
279:   /* Create local sequential vectors */
280:   VecCreateSeq(PETSC_COMM_SELF,len,&tmp_in);
281:   VecDuplicate(tmp_in,&tmp_out);

283:   /* Create scatter context */
284:   ISCreateGeneral(PETSC_COMM_SELF,len,idx,&from);
285:   ISCreateGeneral(PETSC_COMM_SELF,len,idx,&to);
286:   VecScatterCreate(globalin,from,tmp_in,to,&scatter);
287:   VecScatterBegin(globalin,tmp_in,INSERT_VALUES,SCATTER_FORWARD,scatter);
288: 

290: 
291:   VecScatterEnd(globalin,tmp_in,INSERT_VALUES,SCATTER_FORWARD,scatter);
292: 

294:   /*Extract income array */
295:   VecGetArray(tmp_in,&inptr);

297:   /* Extract outcome array*/
298:   VecGetArray(tmp_out,&outptr);

300:   outptr[0] = xc*inptr[0]+xr*inptr[1]+yr*inptr[m];
301:   outptr[m-1] = 2.0*xl*inptr[m-2]+xc*inptr[m-1]+yr*inptr[m-1+m];
302:   for (i=1; i<m-1; i++) {
303:     outptr[i] = xc*inptr[i]+xl*inptr[i-1]+xr*inptr[i+1]
304:       +yr*inptr[i+m];
305:   }

307:   for (j=1; j<n-1; j++) {
308:     outptr[j*m] = xc*inptr[j*m]+xr*inptr[j*m+1]+
309:       yl*inptr[j*m-m]+yr*inptr[j*m+m];
310:     outptr[j*m+m-1] = xc*inptr[j*m+m-1]+2.0*xl*inptr[j*m+m-1-1]+
311:       yl*inptr[j*m+m-1-m]+yr*inptr[j*m+m-1+m];
312:     for(i=1; i<m-1; i++) {
313:       outptr[j*m+i] = xc*inptr[j*m+i]+xl*inptr[j*m+i-1]+xr*inptr[j*m+i+1]
314:         +yl*inptr[j*m+i-m]+yr*inptr[j*m+i+m];
315:     }
316:   }

318:   outptr[mn-m] = xc*inptr[mn-m]+xr*inptr[mn-m+1]+2.0*yl*inptr[mn-m-m];
319:   outptr[mn-1] = 2.0*xl*inptr[mn-2]+xc*inptr[mn-1]+2.0*yl*inptr[mn-1-m];
320:   for (i=1; i<m-1; i++) {
321:     outptr[mn-m+i] = xc*inptr[mn-m+i]+xl*inptr[mn-m+i-1]+xr*inptr[mn-m+i+1]
322:       +2*yl*inptr[mn-m+i-m];
323:   }

325:   VecRestoreArray(tmp_in,&inptr);
326:   VecRestoreArray(tmp_out,&outptr);

328:   VecScatterCreate(tmp_out,from,globalout,to,&scatter);
329:   VecScatterBegin(tmp_out,globalout,INSERT_VALUES,SCATTER_FORWARD,scatter
330: );
331: 
332:   VecScatterEnd(tmp_out,globalout,INSERT_VALUES,SCATTER_FORWARD,scatter);
333: 
334: 
335:   /* Destroy idx aand scatter */
336:   ISDestroy(from);
337:   ISDestroy(to);
338:   VecScatterDestroy(scatter);

340:   PetscFree(idx);
341:   return 0;
342: }

344: int FormJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *flag,void *ptr)
345: {
346:   Data *data = (Data*)ptr;
347:   Mat A = *AA;
348:   Scalar v[1],one = 1.0;
349:   int idx[1],i,j,row,ierr;
350:   int m,n,mn;

352:   m = data->m;
353:   n = data->n;
354:   mn = (data->m)*(data->n);
355: 
356:   for(i=0; i<mn; i++) {
357:     idx[0] = i;
358:     v[0] = one;
359:     MatSetValues(A,1,&i,1,idx,v,INSERT_VALUES);
360:   }

362:   for(i=0; i<mn-m; i++) {
363:     idx[0] = i+m;
364:     v[0]= one;
365:     MatSetValues(A,1,&i,1,idx,v,INSERT_VALUES);
366:   }

368:   for(i=m; i<mn; i++) {
369:     idx[0] = i-m;
370:     v[0] = one;
371:     MatSetValues(A,1,&i,1,idx,v,INSERT_VALUES);
372:   }

374:   for(j=0; j<n; j++) {
375:     for(i=0; i<m-1; i++) {
376:       row = j*m+i;
377:       idx[0] = j*m+i+1;
378:       v[0] = one;
379:       MatSetValues(A,1,&row,1,idx,v,INSERT_VALUES);
380:     }
381:   }

383:   for(j=0; j<n; j++) {
384:     for(i=1; i<m; i++) {
385:       row = j*m+i;
386:       idx[0] = j*m+i-1;
387:       v[0] = one;
388:       MatSetValues(A,1,&row,1,idx,v,INSERT_VALUES);
389:     }
390:   }
391: 
392:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
393:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);


396:   *flag = SAME_NONZERO_PATTERN;
397:   return 0;
398: }

400: int RHSJacobian(TS ts,double t,Vec x,Mat *AA,Mat *BB,MatStructure *flag,void *ptr)
401: {
402:   Data *data = (Data*)ptr;
403:   Mat A = *AA;
404:   Scalar v[5];
405:   int idx[5],i,j,row,ierr;
406:   int m,n,mn;
407:   double dx,dy,a,epsilon,xc,xl,xr,yl,yr;

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

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

423:   row=0;
424:   v[0] = xc; v[1]=xr; v[2]=yr;
425:   idx[0]=0; idx[1]=2; idx[2]=m;
426:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);

428:   row=m-1;
429:   v[0]=2.0*xl; v[1]=xc; v[2]=yr;
430:   idx[0]=m-2; idx[1]=m-1; idx[2]=m-1+m;
431:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);

433:   for (i=1; i<m-1; i++) {
434:     row=i;
435:     v[0]=xl; v[1]=xc; v[2]=xr; v[3]=yr;
436:     idx[0]=i-1; idx[1]=i; idx[2]=i+1; idx[3]=i+m;
437:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
438:   }

440:   for (j=1; j<n-1; j++) {
441:     row=j*m;
442:     v[0]=xc; v[1]=xr; v[2]=yl; v[3]=yr;
443:     idx[0]=j*m; idx[1]=j*m; idx[2]=j*m-m; idx[3]=j*m+m;
444:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
445: 
446:     row=j*m+m-1;
447:     v[0]=xc; v[1]=2.0*xl; v[2]=yl; v[3]=yr;
448:     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;
449:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);

451:     for(i=1; i<m-1; i++) {
452:       row=j*m+i;
453:       v[0]=xc; v[1]=xl; v[2]=xr; v[3]=yl; v[4]=yr;
454:       idx[0]=j*m+i; idx[1]=j*m+i-1; idx[2]=j*m+i+1; idx[3]=j*m+i-m;
455:       idx[4]=j*m+i+m;
456:       MatSetValues(A,1,&row,5,idx,v,INSERT_VALUES);
457:     }
458:   }

460:   row=mn-m;
461:   v[0] = xc; v[1]=xr; v[2]=2.0*yl;
462:   idx[0]=mn-m; idx[1]=mn-m+1; idx[2]=mn-m-m;
463:   MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);
464: 
465:   row=mn-1;
466:   v[0] = xc; v[1]=2.0*xl; v[2]=2.0*yl;
467:   idx[0]=mn-1; idx[1]=mn-2; idx[2]=mn-1-m;
468:   MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);

470:   for (i=1; i<m-1; i++) {
471:     row=mn-m+i;
472:     v[0]=xl; v[1]=xc; v[2]=xr; v[3]=2.0*yl;
473:     idx[0]=mn-m+i-1; idx[1]=mn-m+i; idx[2]=mn-m+i+1; idx[3]=mn-m+i-m;
474:     MatSetValues(A,1,&row,4,idx,v,INSERT_VALUES);
475:   }


478:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
479:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);


482:   *flag = SAME_NONZERO_PATTERN;
483:   return 0;
484: }

486: int RHSFunction(TS ts,double t,Vec globalin,Vec globalout,void *ctx)
487: {
489:   SNES snes = PETSC_NULL;

491:   FormFunction(snes,globalin,globalout,ctx);


494:   return 0;
495: }